
#include "db_driver.h"
#include "libevent_cpp/include/include_all.h"
#include "svr_util/include/stl_boost.h"
#include "svr_util/include/str_util.h"

using namespace std;
using namespace lc;
using namespace su;
using namespace proto;


void proto::Dbproxy::Init(const std::string &ip, uint16_t port, std::function<void()> onInitOk)
{
	gClient.RegFun(&Dbproxy::RevQueryCondForMore, *this, "RevQueryCondForMore");
	gClient.Init(ip.c_str(), port, onInitOk);
}

void proto::Dbproxy::Insert(const proto::BaseTable& data, std::function<void(bool)> ret /*= nullptr*/)
{
	string str;
	L_COND_V(TableCfg::Ins().Pack(data, str));
	if (ret)
	{
		gClient.Call(ret, "Insert", str);
	}
	else
	{
		gClient.CallNoRet("Insert", str);
	}
}

void proto::Dbproxy::Del(const proto::BaseTable& data, std::function<void(bool)> ret /*= nullptr*/)
{
	std::string cond;
	const Table* table = TableCfg::Ins().GetTable(data.TableId());
	L_COND_V(table);
	{//build cond
		const Field* field = table->GetMainKey();
		L_COND_V(field);
		uint8_t* pField = (uint8_t*)&data + field->pOffset;

		cond += field->name;
		cond += "=";
		if (field->type == FieldType::t_string)
		{
			cond += "'" + *(string*)pField + "'";
		}
		else if (field->type == FieldType::t_uint64_t || field->type == FieldType::t_int64_t)
		{
			cond += StrNum::NumToStr(*(uint64_t*)pField);
		}
		else
		{
			L_ERROR("no main key");
			return;
		}
	}
	if (ret)
	{
		gClient.Call(ret, "Del", data.TableId(), cond);
	}
	else
	{
		gClient.Call("Del", data.TableId(), cond);
	}
}

void proto::Dbproxy::QueryCondRaw(uint16_t tableId, const std::string& cond, std::function<void(const std::string&)> ret)
{
	gClient.Call(ret, "QueryCond", tableId, cond);
}

void proto::Dbproxy::QueryCondForMore(uint16_t tableId, const std::string& cond, void(*retCb)(const std::string&), uint32_t limitNum /*= 0*/)
{
	bool ret = m_id2RevQueryFun.insert({ tableId, retCb }).second;
	L_COND_V(ret, "repeated RegQueryCondForMore, id=%d", tableId);
	gClient.CallNoRet("QueryCondForMore", tableId, cond, limitNum);
}

void proto::Dbproxy::QueryCondPartly(uint16_t tableId, const std::string& cond, const std::vector<std::string>& vecFieldName, std::function<void(const std::string&)> ret)
{
	gClient.Call(ret, "QueryCondPartly", tableId, cond, vecFieldName);
}

void proto::Dbproxy::Update(const proto::BaseTable& obj) //更新数据，没填值的字段不会更新
{
	std::string str;
	TableCfg::Ins().Pack(obj, str);

	gClient.Call("Update", str);
}

void proto::Dbproxy::Sql(const std::string& sql)
{
	gClient.CallNoRet("Sql", sql);
}

void proto::Dbproxy::RevQueryCondForMore(uint16_t tableId, const std::string& data)
{
	auto it = m_id2RevQueryFun.find(tableId);
	L_COND_V(it != m_id2RevQueryFun.end(), "miss handle table function. id %d", tableId);
	L_COND_V(it->second);
	(it->second)(data);
}

